package com.core.cloudbusiness.system.login.service.Impl;

import cn.hutool.core.util.IdUtil;
import cn.hutool.crypto.SecureUtil;
import com.alibaba.fastjson.JSON;
import com.core.cloudbusiness.system.log.service.LoginLogService;
import com.core.cloudbusiness.system.login.service.CloudSystemLoginService;
import com.core.cloudbusiness.system.user.mapper.CloudSystemUserMapper;
import com.core.cloudbusiness.system.user.service.CloudSystemUserService;
import com.core.cloudcommon.CommonCustomException;
import com.core.cloudcommon.CommonInteger;
import com.core.cloudcommon.redis.service.CloudRedisTemplateService;
import com.core.cloudcommon.redis.vo.CloudRedisVO;
import com.core.cloudcommon.security.*;
import com.core.cloundbusinessapi.system.login.dto.CloudSystemLoginDTO;
import com.core.cloudcommon.enums.CloudSystemLoginResultCode;
import com.core.cloudcommon.security.UserInfo;
import com.core.cloundbusinessapi.system.login.vo.CloudSystemLoginVO;
import com.core.cloundbusinessapi.system.user.dto.CloudSystemUserDTO;

import com.core.cloundbusinessapi.system.user.vo.CloudSystemQueryListUserVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author =====Lqj=====
 * @className CloudSystemLoginServiceImpl
 * @description
 * @create 2024/11/16 13:15
 **/
@Slf4j
@Service
public class CloudSystemLoginServiceImpl implements CloudSystemLoginService {

    @Autowired
    private CloudSystemUserService cloudSystemUserService;

    @Autowired
    private CloudRedisTemplateService cloudRedisTemplateService;

    @Autowired
    private LoginSecurityManager loginSecurityManager;

    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @Autowired
    private ConcurrentLoginManager concurrentLoginManager;

    @Autowired
    private LoginLogService loginLogService;

    @Autowired
    private SmsCodeManager smsCodeManager;

    @Autowired
    private CloudSystemUserMapper cloudSystemUserMapper;

    final String businessType = "loginSms";

    final Long time = 86400L;


    @Override
    public CloudSystemLoginDTO login(CloudSystemLoginVO cloudSystemLoginVO) {
        return login(cloudSystemLoginVO, null);
    }

    @Override
    public CloudSystemLoginDTO login(CloudSystemLoginVO cloudSystemLoginVO, HttpServletRequest request) {
        if (Objects.isNull(cloudSystemLoginVO)) {
            throw new CommonCustomException(CloudSystemLoginResultCode.CODE200001.getCode(), CloudSystemLoginResultCode.CODE200001.getMsg());
        }

        log.info("云系统登陆请求参数：" + JSON.toJSONString(cloudSystemLoginVO));

        // 确定登录账户标识
        String loginAccount = cloudSystemLoginVO.getWay() == 1 ?
            cloudSystemLoginVO.getPhone() : cloudSystemLoginVO.getUserName();

        // 安全检查：账户锁定检查
        loginSecurityManager.checkAccountLock(loginAccount);

        // 查询用户信息
        CloudSystemQueryListUserVO cloudSystemQueryListUserVO = new CloudSystemQueryListUserVO();
        cloudSystemQueryListUserVO.setUserName(cloudSystemLoginVO.getUserName());
        cloudSystemQueryListUserVO.setPhone(cloudSystemLoginVO.getPhone());
        List<CloudSystemUserDTO> cloudSystemUserDTOS = cloudSystemUserService.queryList(cloudSystemQueryListUserVO);

        if (cloudSystemUserDTOS.isEmpty()) {
            // 记录登录失败
            loginSecurityManager.recordLoginFail(loginAccount);
            throw new CommonCustomException(CloudSystemLoginResultCode.CODE200002.getCode(), CloudSystemLoginResultCode.CODE200002.getMsg());
        }
        CloudSystemUserDTO cloudSystemUserDTO = cloudSystemUserDTOS.get(CommonInteger.Integer0);

        try {
            // 根据登录方式进行验证
            CloudSystemLoginDTO result;
            if (CommonInteger.Integer1.equals(cloudSystemLoginVO.getWay())) {
                // 手机验证码登录
                result = handleSmsLogin(cloudSystemLoginVO, cloudSystemUserDTO, loginAccount);
            } else {
                // 账号密码登录
                result = handlePasswordLogin(cloudSystemLoginVO, cloudSystemUserDTO, loginAccount);
            }

            // 异步记录登录成功日志
            if (request != null) {
                loginLogService.recordLoginLogAsync(cloudSystemLoginVO, cloudSystemUserDTO,
                    true, null, request, result.getToken());
            }

            return result;

        } catch (CommonCustomException e) {
            // 登录失败，记录失败次数
            loginSecurityManager.recordLoginFail(loginAccount);

            // 异步记录登录失败日志
            if (request != null) {
                loginLogService.recordLoginLogAsync(cloudSystemLoginVO, cloudSystemUserDTO,
                    false, e.getMessage(), request, null);
            }

            throw e;
        }
    }

    /**
     * 处理手机验证码登录
     */
    private CloudSystemLoginDTO handleSmsLogin(CloudSystemLoginVO cloudSystemLoginVO,
                                             CloudSystemUserDTO cloudSystemUserDTO,
                                             String loginAccount) {
        if (null == cloudSystemLoginVO.getPhone() || null == cloudSystemLoginVO.getSmsCode()) {
            throw new CommonCustomException(CloudSystemLoginResultCode.CODE2000010.getCode(),
                                          CloudSystemLoginResultCode.CODE2000010.getMsg());
        }

        // 使用新的短信验证码管理器验证
        boolean verifyResult = smsCodeManager.verifyCode(
            cloudSystemLoginVO.getPhone(),
            cloudSystemLoginVO.getSmsCode().toString(),
            businessType
        );

        if (!verifyResult) {
            throw new CommonCustomException(CloudSystemLoginResultCode.CODE200009.getCode(),
                                          CloudSystemLoginResultCode.CODE200009.getMsg());
        }

        // 验证成功，清除失败记录
        loginSecurityManager.clearLoginFail(loginAccount);
        loginSecurityManager.clearSmsVerifyFail(cloudSystemLoginVO.getPhone());

        // 生成登录信息
        CloudSystemLoginDTO loginDTO = createLoginDTO(cloudSystemUserDTO, cloudSystemLoginVO);

        // 缓存token
        long tokenTime = getTokenExpireTime(cloudSystemLoginVO.getRememberMe());
        cloudRedisTemplateService.set(new CloudRedisVO(loginDTO.getToken(), JSON.toJSONString(loginDTO), tokenTime));

        // 更新登录时间
        cloudSystemUserService.updateLogTime(cloudSystemUserDTO.getId());

        // 注意：使用新的短信验证码管理器后，验证码会自动标记为已使用，无需手动删除

        return loginDTO;
    }

    /**
     * 处理账号密码登录
     */
    private CloudSystemLoginDTO handlePasswordLogin(CloudSystemLoginVO cloudSystemLoginVO,
                                                  CloudSystemUserDTO cloudSystemUserDTO,
                                                  String loginAccount) {
        // 验证密码
        String password = SecureUtil.md5(cloudSystemLoginVO.getPassWord() + cloudSystemUserDTO.getSalt());
        if (!password.equals(cloudSystemUserDTO.getPassWord())) {
            throw new CommonCustomException(CloudSystemLoginResultCode.CODE200003.getCode(),
                                          CloudSystemLoginResultCode.CODE200003.getMsg());
        }

        // 验证成功，清除失败记录
        loginSecurityManager.clearLoginFail(loginAccount);

        // 生成登录信息
        CloudSystemLoginDTO loginDTO = createLoginDTO(cloudSystemUserDTO, cloudSystemLoginVO);

        // 缓存token
        long tokenTime = getTokenExpireTime(cloudSystemLoginVO.getRememberMe());
        cloudRedisTemplateService.set(new CloudRedisVO(loginDTO.getToken(), JSON.toJSONString(loginDTO), tokenTime));

        // 更新登录时间
        cloudSystemUserService.updateLogTime(cloudSystemUserDTO.getId());

        // 不返回敏感信息
        loginDTO.setCloudSystemUserDTO(null);

        return loginDTO;
    }

    /**
     * 创建登录DTO
     */
    private CloudSystemLoginDTO createLoginDTO(CloudSystemUserDTO userDTO, CloudSystemLoginVO loginVO) {
        log.info("开始创建登录DTO，用户ID: {}", userDTO.getId());

        CloudSystemLoginDTO loginDTO = new CloudSystemLoginDTO();
        loginDTO.setId(userDTO.getId());
        loginDTO.setLoginTime(userDTO.getLoginTime());

        try {
            // 使用JWT生成token
            log.info("开始生成JWT Token");
            String jwtToken = jwtTokenUtil.generateToken(userDTO, loginVO.getRememberMe());
            log.info("JWT Token生成成功，长度: {}", jwtToken != null ? jwtToken.length() : 0);

            loginDTO.setToken(jwtToken);
            loginDTO.setTokenTime(Boolean.TRUE.equals(loginVO.getRememberMe()) ? 24 * 30 : 24); // 记住登录30天，否则24小时
            loginDTO.setCloudSystemUserDTO(userDTO);

            // 处理并发登录控制
            log.info("开始处理并发登录控制");
            String deviceId = loginVO.getDeviceId() != null ? loginVO.getDeviceId() : "unknown";
            String deviceName = loginVO.getDeviceName() != null ? loginVO.getDeviceName() : "未知设备";
            String deviceType = getDeviceTypeName(loginVO.getClientType());
            long tokenExpireTime = getTokenExpireTime(loginVO.getRememberMe());

            concurrentLoginManager.handleUserLogin(
                userDTO.getId(),
                jwtToken,
                deviceId,
                deviceName,
                deviceType,
                "unknown", // IP会在Controller层设置
                tokenExpireTime
            );
            log.info("并发登录控制处理完成");

        } catch (Exception e) {
            log.error("创建登录DTO过程中出现异常: {}", e.getMessage(), e);
            throw e;
        }

        log.info("登录DTO创建完成");
        return loginDTO;
    }

    /**
     * 获取设备类型名称
     */
    private String getDeviceTypeName(Integer clientType) {
        if (clientType == null) {
            return "未知";
        }
        switch (clientType) {
            case 0: return "Web端";
            case 1: return "iOS端";
            case 2: return "安卓端";
            case 3: return "Windows端";
            case 4: return "macOS端";
            case 5: return "鸿蒙端";
            default: return "未知设备";
        }
    }

    /**
     * 获取Token过期时间
     */
    private long getTokenExpireTime(Boolean rememberMe) {
        if (Boolean.TRUE.equals(rememberMe)) {
            return 30 * 24 * 60 * 60L; // 30天
        } else {
            return time; // 默认24小时
        }
    }

    @Override
    public void exit(String token) {
        exit(token, null);
    }

    @Override
    public void exit(String token, HttpServletRequest request) {
        if (null == token) {
            throw new CommonCustomException(CloudSystemLoginResultCode.CODE200004.getCode(),
                                          CloudSystemLoginResultCode.CODE200004.getMsg());
        }

        try {
            // 记录退出日志
            if (request != null) {
                loginLogService.recordLogoutLog(token, request);
            }

            // 获取用户ID
            Long userId = concurrentLoginManager.getUserIdFromToken(token);
            if (userId != null) {
                // 从并发登录管理中移除
                concurrentLoginManager.handleUserLogout(userId, token);
            }

            // 从Redis中删除token
            cloudRedisTemplateService.del(token);

            log.info("用户退出登录成功，token: {}", token.substring(0, Math.min(10, token.length())) + "...");

        } catch (Exception e) {
            log.error("退出登录失败: {}", e.getMessage());
            // 即使出错也要删除token
            cloudRedisTemplateService.del(token);
        }
    }

    final List<Integer> digits = Arrays.asList(CommonInteger.Integer0, CommonInteger.Integer1,
            CommonInteger.Integer2, CommonInteger.Integer3,
            CommonInteger.Integer4, CommonInteger.Integer5,
            CommonInteger.Integer6, CommonInteger.Integer7,
            CommonInteger.Integer8, CommonInteger.Integer9);

    @Override
    public boolean sendSms(String phone) {
        return sendSms(phone, null);
    }

    /**
     * 发送短信验证码（包含IP信息）
     */
    public boolean sendSms(String phone, String ip) {
        if (StringUtils.isEmpty(phone)) {
            throw new CommonCustomException(CloudSystemLoginResultCode.CODE200005.getCode(),
                                          CloudSystemLoginResultCode.CODE200005.getMsg());
        }

        // 手机号格式验证
        if (!phone.matches("^1[3-9]\\d{9}$")) {
            throw new CommonCustomException(CloudSystemLoginResultCode.CODE200005.getCode(),
                                          "手机号格式不正确");
        }

        log.info("发送验证码请求参数：" + phone);

        // 查询用户是否存在
        CloudSystemQueryListUserVO cloudSystemQueryListUserVO = new CloudSystemQueryListUserVO();
        cloudSystemQueryListUserVO.setPhone(phone);
        List<CloudSystemUserDTO> cloudSystemUserDTOS = cloudSystemUserService.queryList(cloudSystemQueryListUserVO);
        if (cloudSystemUserDTOS.isEmpty()) {
            throw new CommonCustomException(CloudSystemLoginResultCode.CODE200007.getCode(),
                                          CloudSystemLoginResultCode.CODE200007.getMsg());
        }

        // 使用新的短信验证码管理器
        String clientIp = ip != null ? ip : "unknown";
        String code = smsCodeManager.generateAndSendCode(phone, clientIp, businessType);

        log.info("验证码发送成功，手机号: {}", phone);

        return true;
    }

    /**
     * 生成安全的6位数字验证码
     */
    private String generateSecureCode() {
        java.security.SecureRandom random = new java.security.SecureRandom();
        StringBuilder code = new StringBuilder();
        for (int i = 0; i < 6; i++) {
            code.append(random.nextInt(10));
        }
        return code.toString();
    }

    @Override
    public CloudSystemLoginDTO refreshToken(String oldToken) {
        try {
            // 验证旧token是否有效
            if (jwtTokenUtil.isTokenExpired(oldToken)) {
                throw new CommonCustomException(CloudSystemLoginResultCode.CODE200022.getCode(),
                                              "Token已过期，请重新登录");
            }

            // 检查token是否在并发登录管理中有效
            if (!concurrentLoginManager.isTokenValid(oldToken)) {
                throw new CommonCustomException(CloudSystemLoginResultCode.CODE200022.getCode(),
                                              "Token已失效，请重新登录");
            }

            // 从旧token获取用户信息
            UserInfo userInfo = jwtTokenUtil.getUserFromToken(oldToken);

            // 根据用户ID查询完整的用户信息
            CloudSystemUserDTO userDTO = cloudSystemUserMapper.selectById(userInfo.getId());
            if (userDTO == null) {
                throw new CommonCustomException(CloudSystemLoginResultCode.CODE200002.getCode(), "用户不存在或已被删除");
            }

            // 生成新token
            Boolean rememberMe = jwtTokenUtil.getClaimFromToken(oldToken, claims ->
                (Boolean) claims.get("rememberMe"));
            String newToken = jwtTokenUtil.refreshToken(oldToken);

            // 更新并发登录管理中的token
            Long userId = concurrentLoginManager.getUserIdFromToken(oldToken);
            if (userId != null) {
                // 先退出旧token
                concurrentLoginManager.handleUserLogout(userId, oldToken);

                // 添加新token
                long tokenExpireTime = getTokenExpireTime(rememberMe);
                concurrentLoginManager.handleUserLogin(
                    userId,
                    newToken,
                    "refresh",
                    "刷新设备",
                    "刷新",
                    "unknown",
                    tokenExpireTime
                );
            }

            // 构建返回结果
            CloudSystemLoginDTO loginDTO = new CloudSystemLoginDTO();
            loginDTO.setId(userDTO.getId());
            loginDTO.setToken(newToken);
            loginDTO.setTokenTime(Boolean.TRUE.equals(rememberMe) ? 24 * 30 : 24);
            loginDTO.setLoginTime(new Date());

            // 更新Redis中的token信息
            long tokenTime = getTokenExpireTime(rememberMe);
            cloudRedisTemplateService.del(oldToken); // 删除旧token
            cloudRedisTemplateService.set(new CloudRedisVO(newToken, JSON.toJSONString(loginDTO), tokenTime));

            log.info("用户 {} Token刷新成功", userDTO.getId());
            return loginDTO;

        } catch (CommonCustomException e) {
            throw e;
        } catch (Exception e) {
            log.error("Token刷新失败: {}", e.getMessage());
            throw new CommonCustomException(CloudSystemLoginResultCode.CODE200023.getCode(),
                                          "Token刷新失败，请重新登录");
        }
    }

    @Override
    public boolean kickOutOtherDevices(String token) {
        try {
            // 验证token
            if (jwtTokenUtil.isTokenExpired(token)) {
                throw new CommonCustomException(CloudSystemLoginResultCode.CODE200022.getCode(),
                                              "Token已过期");
            }

            // 获取用户ID
            Long userId = concurrentLoginManager.getUserIdFromToken(token);
            if (userId == null) {
                throw new CommonCustomException(CloudSystemLoginResultCode.CODE200022.getCode(),
                                              "Token无效");
            }

            // 踢出其他设备
            concurrentLoginManager.kickOutOtherSessions(userId, token);

            log.info("用户 {} 踢出其他设备登录成功", userId);
            return true;

        } catch (CommonCustomException e) {
            throw e;
        } catch (Exception e) {
            log.error("踢出其他设备失败: {}", e.getMessage());
            return false;
        }
    }
}
